-
Notifications
You must be signed in to change notification settings - Fork 6.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Peek] Fix memory leak caused by unmanaged bitmaps not being freed #34484
Conversation
@microsoft-github-policy-service agree |
@@ -103,12 +103,6 @@ | |||
</Page> | |||
</ItemGroup> | |||
|
|||
<ItemGroup> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like unrelated changes here. Is this needed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was me removing a duplicate entry I found in the project file, and it's not related to the memory leak issue. I can split it out into a separate PR if you'd prefer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
Tested the fix and also performed a sanity check of Peek.
Based on what the fix was, I still don't have a good explanation for what could cause this behaviour we observed earlier, but maybe that's not critical to address now.
It would be good to make the ImagePreviewer::Dispose
workflow idempotent, as that is a requirement of IDisposable
. Currently, calling Dispose
multiple times would result in multiple deletes of native handles. But that does not seem to be happening in practice, so we can defer that for later.
Thank you for approving the merge, @drawbyperpetual ! I can speak to the strange behaviour you were seeing previously, where the increase in private bytes used was not as prevalent when the same files were previewed again: this could be because of the thumbnail retrieval code in Peek and the relationship with the Windows thumbnail cache. You are 'priming' the cache by previewing the images, as Peek always calls the Shell thumbnail retrieval/creation routine for every image, even when the full size image loads correctly. This was the fundamental 'tell' of the memory leak issue, as the thumbnail bitmaps are unmanaged and never freed. I've recently raised an issue about the unnecessary thumbnail generation as #34490 . In the majority of cases in my testing, the bitmaps are never used, so the #34490 fix actually saves a considerable amount of memory use and subsequent garbage collection (75%+ GC reduction). I totally agree about the existing |
@daverayment as FYI, we've been heads down trying to get ship .84 and stabilize based on feedback. We appreciate the PRs here! |
@crutkas Thanks! It's a privilege to be able to contribute, and there's certainly no rush. Best of luck with the upcoming release 😀 |
Thanks a lot for the contribution! Merging this in! |
Summary of the Pull Request
Fixes the Peek PowerToy leaking unmanaged resources associated with bitmaps when using the
ImagePreviewer
. Also ensures any Previewer implementingIDisposable
will be correctly disposed.PR Checklist
Detailed Description of the Pull Request / Additional comments
The Peek PowerToy creates a Previewer for each item as the user navigates a folder. For the ImagePreviewer, a
Clear
method is provided which cleans up unmanaged resources, including bitmaps created for preview thumbnails. Unfortunately,Clear
is not called on the old Previewer before a new instance is created, leading to unreachable resources which are never freed. This PR ensuresDispose
is called on a Previewer if it implementsIDisposable
. ImagePreviewer callsClear
within itsDispose
, which fixes the leak.Validation Steps Performed
Manual validation:
PowerToys.Peek.UI
exe in VS, where the memory leak manifests.Byte[]
instances were present in the heap snapshot.Before Fix
Despite garbage collection, unmanaged resources are not freed, leading to an ever-increasing amount of memory used - nearly 2GB in this example.
After Fix